// Package bookmark impliments bookmarks in the browser.
package bookmark

import (
	"fmt"
	"net/http"
	"time"

	"code.google.com/awwwe-browser/auralvm/conversation"
	"code.google.com/awwwe-browser/auralvm/param"
	"code.google.com/awwwe-browser/auralvm/setting"
	"code.google.com/awwwe-browser/data"
)

// Alternative HTTP handler for sending data back to the view.
var NextContinuer func(http.ResponseWriter, *http.Request, string)
// Final alternative HTTP handler for sending data back to the view.
var StopContinuer func(http.ResponseWriter, *http.Request, string)

// A browser book mark.
type Bookmark struct {
	Key   string
	Title string
	URL   string
}

// BuildBookmark constructs a bookmark.
func BuildBookmark() Bookmark {
	var v Bookmark
	var t time.Time
	t = time.Now()
	v.Key = t.String()
	return v
}

// CountBookmarks returns the number of bookmarks that the user has stored in the bookmarks file.
func CountBookmarks() int {
	var bookmarks SliceBookmark
	bookmarks = GetBookmarks()
	return bookmarks.Len()
}

// HandlerBookmarkListTools handles the listing the book mark tools to the view.
func HandlerBookmarkListTools(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	ContinuerBookmarkListTools(w, r, data.EmptyString, -1, true)
}

// ContinuerBookmarkListTools continues what HandlerBookmarkListTools started.
func ContinuerBookmarkListTools(w http.ResponseWriter, r *http.Request, intro string, startoptionsat int, continueon bool) {
	var err error
	var conv *conversation.Conversation
	var option conversation.APIOption
	var jsonbb []byte
	conv = conversation.NewConversation()
	conv.Type = conversation.ConversationTypeOptions
	conv.Intro = intro
	conv.InitialIndex = startoptionsat
	conv.Header.Append("These are the book mark tools.")
	if setting.BrowserSettings.HelpLevel != setting.SettingHelpLevel3 {
		// a lot of help or a little help.
		// add helpful
		conv.Helpful = " I will iterate through the names of each of the tools. After i say the name of a tool, say yes, if you want to use that tool."
	}
	if setting.BrowserSettings.HelpLevel == setting.SettingHelpLevel1 {
		// a lot of help
		// add more helpful
		conv.MoreHelpful = " You may say, yes, back, restart, finish, help, pause, or quit."
	}
	conv.Footer = "That is the end of the list of book mark tools."
	conv.CallHelp.Package = param.Package
	conv.CallHelp.Object = "browser"
	conv.CallHelp.Method = "listtools"
	// listen tool
	option = conversation.BuildAPIOption()
	option.VXMLs.Append("Open a book marked web page in a new tab.")
	option.CallYes.Package = param.Package
	option.CallYes.Object = "bookmark"
	option.CallYes.Method = "listtolisten"
	option.CallYes.Arguments[param.ParamSourceObject] = "bookmark"
	option.CallYes.Arguments[param.ParamSourceMethod] = "listtools"
	option.CallYes.Arguments[param.ParamSourceOptionIndex] = "1"
	conv.Options = append(conv.Options, option)
	// remove tool
	option = conversation.BuildAPIOption()
	option.VXMLs.Append("Remove a book mark.")
	option.CallYes.Package = param.Package
	option.CallYes.Object = "bookmark"
	option.CallYes.Method = "listtoremove"
	option.CallYes.Arguments[param.ParamSourceObject] = "browser"
	option.CallYes.Arguments[param.ParamSourceMethod] = "listtools"
	option.CallYes.Arguments[param.ParamSourceOptionIndex] = "0"
	conv.Options = append(conv.Options, option)
	// serialize the conversation
	jsonbb, err = conv.Marshal()
	if err == nil {
		w.Write(jsonbb)
	} else {
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			// internal server error
			StopContinuer(w, r, intro)
		}
	}
}

// HandlerBookmarkListToListen handles the listing the book marks for listening to the view.
func HandlerBookmarkListToListen(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	ContinuerBookmarkListToListen(w, r, data.EmptyString, -1, true)
}

// ContinuerBookmarkListToListen continues what HandlerBookmarkListToListen started..
func ContinuerBookmarkListToListen(w http.ResponseWriter, r *http.Request, intro string, startoptionsat int, continueon bool) {
	var err error
	var conv *conversation.Conversation
	var option conversation.APIOption
	var bookmark *Bookmark
	var bookmarks SliceBookmark
	var i, length, last int
	var jsonbb []byte
	bookmarks = GetBookmarks()
	if bookmarks.Len() == 0 {
		intro = "You do not have any book marks yet."
		NextContinuer(w, r, intro)
		return
	}
	conv = conversation.NewConversation()
	conv.Type = conversation.ConversationTypeOptions
	conv.Intro = intro
	conv.InitialIndex = startoptionsat
	conv.Header.Append("This tool lets you open a book mark in a new tab. ")
	if setting.BrowserSettings.HelpLevel != setting.SettingHelpLevel3 {
		// a lot of help or a little help.
		// add helpful
		conv.Helpful = "I will iterate through the names of every web page which you have book marked. After i say the name of a web page, say yes, if you want to open the web page and listen to it."
	}
	if setting.BrowserSettings.HelpLevel == setting.SettingHelpLevel1 {
		// a lot of help
		// add more helpful
		conv.MoreHelpful = " You may say, yes, back, restart, finish, help, pause, or quit."
	}
	conv.Footer = "That is the end of the list of book marks."
	conv.CallHelp.Package = param.Package
	conv.CallHelp.Object = "bookmark"
	conv.CallHelp.Method = "listtools"
	conv.InitialIndex = 0
	length = bookmarks.Len()
	last = length - 1
	for i = 0; i < length; i++ {
		bookmark = bookmarks.AtIndex(i)
		option = conversation.BuildAPIOption()
		option.VXMLs.Append(bookmark.Title)
		option.CallYes.Package = param.Package
		option.CallYes.Object = "tab"
		option.CallYes.Method = "opennew"
		option.CallYes.Arguments[param.ParamTabURL] = bookmark.URL
		if i < last {
			// if a tab is not able to open then the vm should continue with listing bookmarks to open.
			option.CallYes.Arguments[param.ParamSourceObject] = "bookmark"
			option.CallYes.Arguments[param.ParamSourceMethod] = "listtoopen"
			option.CallYes.Arguments[param.ParamSourceOptionIndex] = fmt.Sprintf("%d", i)
		} else {
			// if a tab is not able to open then the vm should continue with listing the list of bookmark tools.
			option.CallYes.Arguments[param.ParamSourceObject] = "bookmark"
			option.CallYes.Arguments[param.ParamSourceMethod] = "listtools"
			option.CallYes.Arguments[param.ParamSourceOptionIndex] = "0"
		}
		conv.Options = append(conv.Options, option)
	}
	// serialize the conversation
	jsonbb, err = conv.Marshal()
	if err == nil {
		w.Write(jsonbb)
	} else {
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			// internal server error
			StopContinuer(w, r, intro)
		}
	}
}

// HandlerBookmarkListToRemove lists book marks for removal to the view.
func HandlerBookmarkListToRemove(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	ContinuerBookmarkListToRemove(w, r, data.EmptyString, -1, true)
}

// ContinuerBookmarkListToRemove continues what HandlerBookmarkListToRemove started.
func ContinuerBookmarkListToRemove(w http.ResponseWriter, r *http.Request, intro string, startoptionsat int, continueon bool) {
	var err error
	var conv *conversation.Conversation
	var option conversation.APIOption
	var bookmark *Bookmark
	var bookmarks SliceBookmark
	var i, length int
	var jsonbb []byte
	bookmarks = GetBookmarks()
	if bookmarks.Len() == 0 {
		intro = "You do not have any book marks yet."
		NextContinuer(w, r, intro)
		return
	}
	conv = conversation.NewConversation()
	conv.Type = conversation.ConversationTypeOptions
	conv.Intro = intro
	conv.InitialIndex = startoptionsat
	conv.Header.Append("This tool lets you remove a book mark.")
	if setting.BrowserSettings.HelpLevel != setting.SettingHelpLevel3 {
		// a lot of help or a little help.
		// add helpful
		conv.Helpful = "I will iterate through the names of every web page which you have book marked. After i say the name of a web page, say yes, if you want to remove that book mark."
	}
	if setting.BrowserSettings.HelpLevel == setting.SettingHelpLevel1 {
		// a lot of help
		// add more helpful
		conv.MoreHelpful = " You may say, yes, back, restart, finish, help, pause, or quit."
	}
	conv.Footer = "That is the end of the list of book marks."
	conv.CallHelp.Package = param.Package
	conv.CallHelp.Object = "bookmark"
	conv.CallHelp.Method = "listtools"
	conv.InitialIndex = 0
	length = bookmarks.Len()
	for i = 0; i < length; i++ {
		bookmark = bookmarks.AtIndex(i)
		option = conversation.BuildAPIOption()
		option.VXMLs.Append(bookmark.Title)
		option.CallYes.Package = param.Package
		option.CallYes.Object = "bookmark"
		option.CallYes.Method = "remove"
		option.CallYes.Arguments[param.ParamTabBookMarkKey] = bookmark.Key
		if i < length-1 {
			// after removing a tab the vm should continue with listing bookmarks to remove.
			option.CallYes.Arguments[param.ParamSourceObject] = "bookmark"
			option.CallYes.Arguments[param.ParamSourceMethod] = "listtoremove"
			option.CallYes.Arguments[param.ParamSourceOptionIndex] = fmt.Sprintf("%d", i)
		} else {
			// after removing a tab the vm should continue with listing the bookmark tools.
			option.CallYes.Arguments[param.ParamSourceObject] = "bookmark"
			option.CallYes.Arguments[param.ParamSourceMethod] = "listtools"
			option.CallYes.Arguments[param.ParamSourceOptionIndex] = "0"
		}
		conv.Options = append(conv.Options, option)
	}
	// serialize the conversation
	jsonbb, err = conv.Marshal()
	if err == nil {
		w.Write(jsonbb)
	} else {
		if continueon {
			NextContinuer(w, r, intro)
		} else {
			// internal server error
			StopContinuer(w, r, intro)
		}
	}
}

// HandlerBookmarkAdd adds a bookmark for the view.
func HandlerBookmarkAdd(w http.ResponseWriter, r *http.Request) {
	var values []string
	var err error
	var bookmark Bookmark
	var bookmarks SliceBookmark
	var intro string
	var ok bool
	bookmark = BuildBookmark()
	r.ParseForm()
	// get the title
	values, ok = r.Form[param.ParamBookMarkTitle]
	if !ok || len(values) != 1 {
		intro = "I was not able to add web page to your book marks because the voice app did not provide the book mark title."
		NextContinuer(w, r, intro)
		return
	}
	bookmark.Title = values[0]
	// get the url
	values, ok = r.Form[param.ParamBookMarkURL]
	if !ok || len(values) != 1 {
		intro = "I was not able to add web page to your book marks because the voice app did not provide the book mark you are ell."
		NextContinuer(w, r, intro)
		return
	}
	bookmark.URL = values[0]
	// add the bookmark
	bookmarks = GetBookmarks()
	bookmarks.Append(&bookmark)
	err = bookmarks.Save()
	if err != nil {
		intro = "I was not able to add web page to your book marks because i was not able to write your book marks file."
		NextContinuer(w, r, intro)
		return
	}
	// return the conversation data
	// tab start
	intro = "I have successfully added the web page to your book marks."
	NextContinuer(w, r, intro)
}

// HandlerBookmarkRemove removes a book mark for the view.
func HandlerBookmarkRemove(w http.ResponseWriter, r *http.Request) {
	var values []string
	var key string
	var err error
	var bookmarks SliceBookmark
	var intro string
	var ok bool
	var i, length int
	r.ParseForm()
	intro = "The book mark was successfully deleted."
	// get the key
	values, ok = r.Form[param.ParamTabBookMarkKey]
	if !ok || len(values) != 1 {
		intro = "I was not able to remove the book mark because the voice app did not provide the book mark key."
		NextContinuer(w, r, intro)
		return
	}
	key = values[0]
	// read the bookmarks file
	bookmarks = GetBookmarks()
	length = bookmarks.Len()
	for i = 0; i < length; i++ {
		if bookmarks.AtIndex(i).Key == key {
			// found the book mark to return.
			bookmarks.Delete(i)
			err = bookmarks.Save()
			if err == nil {
				intro = "The book mark was successfully removed."
				NextContinuer(w, r, intro)
			} else {
				intro = "I was not able to remove the book mark because I was not able to save your book marks file."
				NextContinuer(w, r, intro)
			}
			return
		}
	}
	// book mark not found.
	intro = "I was not able to remove the book mark because the voice app did not provide the correct book mark key."
	NextContinuer(w, r, intro)
	return
}
